﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection.Emit;
using System.Reflection;
using System.Data.SqlClient;
using System.Data.Common;

namespace DymaticMethod
{

    //public class DTOObject
    //{
    //    public Guid Id { get; set; }
    //    public string Name { get; set; }
    //    public string PhoneNumber { get; set; }
    //    public DateTime CreatedDate { get; set; }
    //}

    public class DTOObject
    {
        //public Guid Id { get; set; }
        //public string Name { get; set; }
        //public string PhoneNumber { get; set; }
        //public DateTime CreatedDate { get; set; }
        public Guid Id;
        public string Name;
        public string PhoneNumber;
        public DateTime CreatedDate;
        public Guid Id1;
        public string Name1;
        public string PhoneNumber1;
        public DateTime CreatedDate1;
        public Guid Id2;
        public string Name2;
        public string PhoneNumber2;
        public DateTime CreatedDate2;
        public Guid Id3;
        public string Name3;
        public string PhoneNumber3;
        public DateTime CreatedDate3;
    }

    internal class FieldName
    {
        public const String Id = "Id";
        public const String Name = "Name";
        public const String PhoneNumber = "PhoneNumber";
        public const String CreateDate = "CreatedDate";
        public const String Id1 = "Id1";
        public const String Name1 = "Name1";
        public const String PhoneNumber1 = "PhoneNumber1";
        public const String CreateDate1 = "CreatedDate1";
        public const String Id2 = "Id2";
        public const String Name2 = "Name2";
        public const String PhoneNumber2 = "PhoneNumber2";
        public const String CreateDate2 = "CreatedDate2";
        public const String Id3 = "Id3";
        public const String Name3 = "Name3";
        public const String PhoneNumber3 = "PhoneNumber3";
        public const String CreateDate3 = "CreatedDate3";
    }

    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now);
            var zz = 3;
            for (int i = 1; i < 1000; i++)
            {
                List<DTOObject> x = AutoMapper.Map<IDataReader, DTOObject>(new DataBuilder().BuildDataReader());
                Console.WriteLine(DateTime.Now);
                Console.Write(i);
            }
            var xq = 1;
            //foreach (var item in x)
            //{
            //    Console.Write(item.CreatedDate);
            //}
            //Console.WriteLine(DateTime.Now + "" + x.Count);
            //var ddd = typeof(DTOObject).GetProperty("Id");
            //var x = GetFillMethod<DTOObject>("");
            //var y = x(new DataBuilder().BuildDataReader());
            //var z = 1;
            Console.ReadLine();
        }


        static string[] GetFields(string tableName)
        {

            return new String[] { "Id", "Name", "PhoneNumber", "CreatedDate" };

        }

        public static FillBusinessObject<T> GetFillMethod<T>(string tableName) where T : new()
        {

            Type AType = typeof(T);

            Type[] methodArgs = { typeof(IDataReader) };

            DynamicMethod AFillMethod = new DynamicMethod("", AType, methodArgs, AType);

            ILGenerator il = AFillMethod.GetILGenerator();

            MethodInfo DataReaderGet = typeof(DbDataReader).GetMethod("get_Item", new Type[] { typeof(string) });
            //PropertyInfo DataReaderGet = typeof(DbDataReader).GetProperty("Item");

            ConstructorInfo createInfo = AType.GetConstructor(new Type[0]);

            il.DeclareLocal(AType);

            il.Emit(OpCodes.Newobj, createInfo);

            il.Emit(OpCodes.Stloc_0);

            string[] Fields = GetFields(tableName);

            foreach (string AFieldName in Fields)
            {

                PropertyInfo AProp = AType.GetProperty(AFieldName);

                MethodInfo PropSetMethod = AProp.GetSetMethod();



                il.Emit(OpCodes.Ldloc_0);

                il.Emit(OpCodes.Ldarg_0);

                il.Emit(OpCodes.Ldstr, AFieldName);

                il.Emit(OpCodes.Callvirt, DataReaderGet);

                //il.Emit(OpCodes.Isinst, AProp.PropertyType);



                il.Emit(OpCodes.Callvirt, PropSetMethod);

            }

            il.Emit(OpCodes.Ldloc_0);

            il.Emit(OpCodes.Ret);



            return (FillBusinessObject<T>)AFillMethod.CreateDelegate(typeof(FillBusinessObject<T>));

        }

    }



    public class DataBuilder
    {
        public IDataReader BuildDataReader()
        {
            var resultData = new DataTable();
            resultData.Columns.Add(FieldName.PhoneNumber, typeof(string));
            resultData.Columns.Add(FieldName.Name, typeof(string));
            resultData.Columns.Add(FieldName.CreateDate, typeof(DateTime));
            resultData.Columns.Add(FieldName.Id, typeof(string));
            resultData.Columns.Add(FieldName.PhoneNumber1, typeof(string));
            resultData.Columns.Add(FieldName.Name1, typeof(string));
            resultData.Columns.Add(FieldName.CreateDate1, typeof(DateTime));
            resultData.Columns.Add(FieldName.Id1, typeof(string));
            resultData.Columns.Add(FieldName.PhoneNumber2, typeof(string));
            resultData.Columns.Add(FieldName.Name2, typeof(string));
            resultData.Columns.Add(FieldName.CreateDate2, typeof(DateTime));
            resultData.Columns.Add(FieldName.Id2, typeof(string));
            resultData.Columns.Add(FieldName.PhoneNumber3, typeof(string));
            resultData.Columns.Add(FieldName.Name3, typeof(string));
            resultData.Columns.Add(FieldName.CreateDate3, typeof(DateTime));
            resultData.Columns.Add(FieldName.Id3, typeof(string));
            for (int i = 1; i < 1000; i++)
            {
                var resultDataRow = resultData.NewRow();
                resultDataRow[FieldName.PhoneNumber] = "111-222-3333";
                resultDataRow[FieldName.Name] = "111-222-3333";
                resultDataRow[FieldName.Id] = "111-222-3333";
                resultDataRow[FieldName.CreateDate] = DateTime.Now;
                resultDataRow[FieldName.PhoneNumber1] = "111-222-3333";
                resultDataRow[FieldName.Name1] = "111-222-3333";
                resultDataRow[FieldName.Id1] = "111-222-3333";
                resultDataRow[FieldName.CreateDate1] = DateTime.Now;
                resultDataRow[FieldName.PhoneNumber2] = "111-222-3333";
                resultDataRow[FieldName.Name2] = "111-222-3333";
                resultDataRow[FieldName.Id2] = "111-222-3333";
                resultDataRow[FieldName.CreateDate2] = DateTime.Now;
                resultDataRow[FieldName.PhoneNumber3] = "111-222-3333";
                resultDataRow[FieldName.Name3] = "111-222-3333";
                resultDataRow[FieldName.Id3] = "111-222-3333";
                resultDataRow[FieldName.CreateDate3] = DateTime.Now;
                resultData.Rows.Add(resultDataRow);
            }

            return resultData.CreateDataReader();
        }
    }


    public delegate T FillBusinessObject<T>(IDataReader AReader);



    //创建DynamicMethod：

    public class BusinessSetter
    {

        static string[] GetFields(string tableName)
        {

            return new String[] { "UserID", "UserName", "Email", "Pwd" };

        }

        public static FillBusinessObject<T> GetFillMethod<T>(string tableName) where T : new()
        {

            Type AType = typeof(T);

            Type[] methodArgs = { typeof(IDataReader) };

            DynamicMethod AFillMethod = new DynamicMethod("", AType, methodArgs, AType);

            ILGenerator il = AFillMethod.GetILGenerator();

            MethodInfo DataReaderGet = typeof(SqlDataReader).GetMethod("get_Item", new Type[] { typeof(string) });

            ConstructorInfo createInfo = AType.GetConstructor(new Type[0]);

            il.DeclareLocal(AType);

            il.Emit(OpCodes.Newobj, createInfo);

            il.Emit(OpCodes.Stloc_0);

            string[] Fields = GetFields(tableName);

            foreach (string AFieldName in Fields)
            {

                PropertyInfo AProp = AType.GetProperty(AFieldName);

                MethodInfo PropSetMethod = AProp.GetSetMethod();



                il.Emit(OpCodes.Ldloc_0);

                il.Emit(OpCodes.Ldarg_0);

                il.Emit(OpCodes.Ldstr, AFieldName);

                il.Emit(OpCodes.Callvirt, DataReaderGet);

                il.Emit(OpCodes.Isinst, AProp.PropertyType);



                il.Emit(OpCodes.Callvirt, PropSetMethod);

            }

            il.Emit(OpCodes.Ldloc_0);

            il.Emit(OpCodes.Ret);



            return (FillBusinessObject<T>)AFillMethod.CreateDelegate(typeof(FillBusinessObject<T>));

        }

    }

}
